C++ 标准模板库(Standard Template Library,STL):STL 的代码从广义上讲分为三类:algorithm(算法)、container(容器)和 iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方法,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
以下主讲 container(容器)和 iterator(迭代器)。
- 使用 STL 一般要使用
std的命名空间
vector
vector,向量,可以理解为”变长数组“。添加 vector 头文件即可使用 vector 了。
-
vector 的定义
1
vector<typename> name;
- 这里的
typename可以是任何基本类型、结构体,也可以是 STL 标准容器(定义时> >记得隔开,因为有些编译器可能会视为移位操作)
- 这里的
-
vector 内元素访问
可以通过 下标访问 或者是 迭代器:
- 下标访问:与普通数组一样,直接访问
vi[index]即可,下标范围:0 ~ vi.size-1 - 迭代器:类似于 指针,实现了两种自加操作
- 只有
vector和string中允许使用vi.begin() + 整数的写法
- 只有
1
2
3
4
5
6
7
8
9
10
11
12vector<int> vi{1, 2, 3, 4, 5};
// 下标访问
for (int i = 0; i < vi.size(); i++) {
printf("%d ", vi[i]);
}
// 迭代器
for (int i = 0; i < vi.size(); i++) {
printf("%d ", *(vi.begin() + i));
}
for (vector<int>::iterator it = vi.begin(); it != vi.end(); it++) {
printf("%d ", *it);
}vi.begin()是首元素地址,vi.end是尾元素的下一个地址,左闭右开
- 下标访问:与普通数组一样,直接访问
-
vector 常用函数
(1)
push_back(x):在vector后面添加一个元素(2)
pop_back():删除vector的尾元素(3)
size():返回元素个数,unsigned类型,一般直接用%d也不会出问题(4)
clear():清空vector(5)
insert(it, x):向vector的任意迭代器it处插入一个元素 x(6)
erase():删除单个元素、或删除一个区间内的所有元素erase(it):即删除迭代器 it 对应的元素erase(first, last):删除[first, last)内所有的元素
-
常见用途
- 存储数据:可变长度
- 作为邻接表存储图
set
set,集合,是一个 内部自动有序(递增) 且 不含重复元素 的容器。添加 set 头文件即可使用 set 了
-
set 的定义
1
set<typename> name;
typename与vector的定义一样
-
set 内元素访问
set 只能通过 迭代器 访问,且只能通过 自加操作 遍历
1
2
3
4set<int> st {2, 2, 1, 2, 3};
for (set<int>::iterator it = st.begin(); it != st.end(); it++) {
printf("%d ", *it);
} -
set 常用函数
(1)
insert(x):插入元素到set中(2)
find(value):返回set中对应值为 value 的迭代器(3)
erase():删除单个元素、或删除一个区间内的所有元素erase(it):即删除迭代器 it 对应的元素erase(value):value为需要删除元素的值erase(first, last):删除[first, last)内所有的元素
(4)
size():获得set内元素的个数(5)
clear():清除set中的所有元素 -
扩展
set是自动去重并升序排序的multiset元素不唯一unordered_set以散列代替set的红黑树,只去重不排序,速度更快- 可以认为:默认是排序的,即 Java 中的
TreeSet,而unordered_set是HashSet
- 可以认为:默认是排序的,即 Java 中的
- 此外还有
unordered_map,使用 hash 的方式,可以认为是 Java 的HashMap,而Map
string
C 中一般使用 char str[] 来存放字符串,但是容易出错,因此 C++ 对字符串常用的需要功能封装成了 string 类型。添加 string 头文件即可使用 string(string.h 和 string 是不一样的头文件)。
-
string 的定义
1
string str = "Eason";
-
string 输入
如果要读入和输出整个字符串,只能用
cin和count:1
2
3string str;
cin >> str;
cout << str;其实也可以用
printf来输出,通过c_str()将string转换为字符数组输出1
printf("%s\n", str.c_str());
-
string 中内容的访问
与
vector一样,可以通过 下标访问 或者是 迭代器:- 下标访问:与字符数组一样,直接访问
str[index]即可,下标范围:0 ~ vi.length-1 - 迭代器:类似于 指针,实现了两种自加操作
- 只有
vector和string中允许使用vi.begin() + 整数的写法
- 只有
1
2
3
4
5
6
7string str = "Eason";
for (int i = 0; i < str.length(); ++i) {
printf("%c", str[i]);
}
for (string::iterator it = str.begin(); it != str.end(); it++) {
printf("%c", *it);
} - 下标访问:与字符数组一样,直接访问
-
string 常用函数
(1)
operator+=:+=的重载,将两个string直接拼接起来(2)
compare operator:两个string可以直接使用==、!=、<、<=、>、>=比较大小,比较规则是 字典序(3)
length()/size():返回string的长度,即存放的字符数(4)
insert():string的插入方式有很多insert(pos, string):在pos对应的位置插入字符串stringinsert(it, begin, end):it为原字符串的欲插入位置,begin、end为待插入字符串的首尾迭代器,将[begin, end)插入到it的位置上
(5)
erase():删除单个元素、删除一个区间内的所有元素erase(it):即删除迭代器 it 对应的字符erase(first, last):删除[first, last)内所有的字符erase(pos, length):删除[pos, pos + length)内的字符,pos为需要开始删除的起始位置,length为删除的字符个数
(6)
clear():清空string中的数据(7)
substr(pos, len):返回从pos开始、长度为len的子串(8)
string::npos:一个常数,值为-1,但由于是unsigned_int类型,用作为find()函数失配时的返回值(9)
find():在字符串中寻找子串find(str):返回str在字符串中第一次出现的位置,如果不出现则返回string::nposfind(str, pos):从字符串的pos开始匹配str
(10)
replace():替换子串str.replace(pos, len, str2):将str从pos开始,长度为len的子串替换为str2str.replace(start, end, str2):把str的[start, end)范围的子串替换成str2
map
map,映射,key 和 value 唯一,且按 key 自动排序,添加头文件 map。
-
map 的定义
1
map<typename1, typename2> mp;
typename1可以用string但是不能使用char[]
-
map 内元素的访问
通过 下标、迭代器 访问
map的下标并不一定是数字,为typename1类型map迭代器有两个键:map可以使用it->first访问键,it->second访问值
-
map 常用函数
(1)
find(key):返回键为key的映射的迭代器(2)
erase():删除单个元素、删除一个区间内的所有元素erase(it):删除迭代器 it 对应的映射erase(key):删除键为key的映射erase(first, last):删除[first, last)内所有的字符
(3)
size():map中映射的对数(4)
clear():清空map -
扩展
multimap可以一个键对多个值unordered_map以散列代替map的红黑树,不排序,速度更快
queue
queue,队列,先进先出(FIFO)的限制性数据结构。引入头文件 queue。
-
queue 的定义
1
queue<typename> name;
-
queue 内元素的访问
queue只能通过front()来访问队首元素、back()来访问队尾元素 -
queue 常用函数
(1)
push(x):将 x 入队列(2)
front()、back():获取队首元素、队尾元素(3)
pop():队首元素出队(4)
empty():判断队列是否为空- 使用
front()、back()前必须判断队列是否为空
- 使用
-
扩展:
- 双端队列(deque) 和 优先队列(priority_queue)
priority_queue
priority_queue,优先队列,底层采用 堆 实现,队首元素是优先级最高的那一个。在 queue 头文件中。
priority_queue 的定义、元素访问、常用函数基本相同。
priority_queue 优先级设置:
-
基本数据类型的优先级设置
1
2
3priority_queue<int> pq; //默认大根堆
priority_queue<int, vector<int>, less<int> > pq;
priority_queue<int, vector<int>, greater<int> > pq;- 第二个参数填写的是来承接底层数据结构堆的容器,一般是填
vector<typename> - 第三个参数对第一个参数的比较类:
less<int>表示数字大的优先级越大,而greater<int>表示数字小的优先级越大
- 第二个参数填写的是来承接底层数据结构堆的容器,一般是填
-
结构体的优先级设置
- 结构体的优先级设置一般通过 重载 < 来实现:
1
2
3
4
5
6
7
8
9
10struct fruit {
string name;
int price;
// 重载 > 会出错,重载 < 可以等价于重载 >
friend bool operator < (fruit a, fruit b) {
return a.price < b.price; // 大根堆
// return a.price > b.price;
}
};- 也可以构造
priority_queue时添加一个类似于cmp的结构体
1
2
3
4
5
6
7
8struct cmp {
bool operator () (fruit a, fruit b) {
// 小根堆
return a.price > b.price;
}
};
priority_queue<fruit, vector<fruit>, cmp > pq;
stack
stack,栈,先进后出(FILO)的数据结构。引入头文件 stack。
-
stack 定义
1
stack<typename> name;
-
stack 内元素的访问
stack只能通过top()来访问栈顶元素 -
stack 常用函数
(1)
push(x):将 x 入栈(2)
top():获得栈顶元素(3)
pop():弹出栈顶元素(4)
empty():判断stack是否为空(5)
size():返回stack内元素的个数
pair
pair,可以理解为一个具有两个元素的简单结构体。引入头文件 utility(map 头文件已添加)。
-
pair 的定义
1
2pair<typename1, typename2> name;
pair<typename1, typename2> name(first, second);也可以临时建立
pair1
2pair<string, string>("name", "Eason");
make_pair("name", "Eason"); //自带函数 -
pair 元素的访问
pair只有两个元素:first和second,只需要按正常结构体访问即可。 -
pair 常用函数
比较操作符:
pair类型数据之间可以直接使用==、!=、<、<=、>、>=比较大小,比较规则是 先 first 再 second -
pair 常见用途
- 代替二元结构体
- 可以直接插入
map
